#ifndef BASE_INCLUDE_FILE_TYPEDEFS_H
#define BASE_INCLUDE_FILE_TYPEDEFS_H

#include "conf.h"
//---------------------------------------------------------
// Define basic types
//---------------------------------------------------------
#include <map>
#include <list>
#include <sstream>
#include <cassert>
#include <limits>
#include <string>
#include <list>
#include <set>
#include <map>
#include <vector>
#include <deque>
#include <queue>

//---------------------------------------------------------
namespace base
{
	// blob:
	template<size_t length>	class blob
	{
	public:
		blob()
		{
			memset(m_data, 0, length);
		}

		blob(const blob<length>& rhs)
		{
			memcpy(m_data, rhs.m_data, length);
		}
	public:
		blob<length> operator=(const blob<length>& rhs)
		{
			if (this != &rhs)
			{
				memcpy(m_data, rhs.m_data, length);
			}
			return *this;
		}

		bool operator==(const blob<length>& rhs)
		{
			return (memcmp(m_data, rhs.m_data, length) == 0);
		}

		bool operator<(const blob<length>& rhs)
		{
			return (memcmp(m_data, rhs.m_data, length) < 0);
		}

		uint8_t operator[](size_t pos) const
		{
			assert(pos < length);
			return m_data[pos];
		}

		uint8_t& operator[](size_t pos)
		{
			assert(pos < length);
			return m_data[pos];
		}
	public:
		uint8_t * begin() { return m_data; }
		uint8_t * end() { return m_data + length; }
		const uint8_t * begin() const { return m_data; }
		const uint8_t * end() const { return m_data + length; }
		size_t size() const { return length; }
	private:
		uint8_t	m_data[length];
	};


	// buffer:
	class buffer
	{
	public:
		buffer():m_data(0), m_size(0) {}
		buffer(void * buf, size_t len):m_data((uint8_t*)buf), m_size(len) {}
		buffer(const buffer& rhs): m_data(rhs.m_data), m_size(rhs.m_size) {}
	public:
		buffer& operator=(const buffer& rhs)
		{
			if (this != &rhs)
			{
				m_data = rhs.m_data;
				m_size = rhs.m_size;
			}
			return *this;
		}
	public:
		bool operator==(const buffer& rhs) const
		{
			return (m_size == rhs.m_size) && (m_data == rhs.m_data);
		}

		bool operator<(const buffer& rhs) const
		{
			return (m_size < rhs.m_size) || (m_data < rhs.m_data);
		}

		uint8_t operator[](size_t pos) const
		{
			assert(pos < m_size);
			assert(m_data != 0);
			return m_data[pos];
		}

		uint8_t& operator[](size_t pos)
		{
			assert(pos < m_size);
			assert(m_data != 0);
			return m_data[pos];
		}
	public:
		uint8_t * begin() { return m_data; }
		uint8_t * end() { return m_data + m_size; }
		const uint8_t * begin() const { return m_data; }
		const uint8_t * end() const { return m_data + m_size; }
		size_t size() const { return m_size; }
	private:
		uint8_t *	m_data;
		size_t		m_size;
	};

}

//---------------------------------------------------------
namespace base
{
	using std::set;
	using std::map;
	using std::pair;
	using std::list;
	using std::deque;
	using std::queue;
	using std::vector;
	using std::multiset;
	using std::multimap;
	using std::basic_string;

	typedef std::map<const std::string, std::string>	dictionary;
	typedef dictionary									properites;
	typedef blob<16>									guid;
}

//---------------------------------------------------------
namespace std
{
	inline std::ostream& operator<<(std::ostream& os, const base::buffer& value)
	{
		const unsigned int maxcount = 16;
		char strbuf[maxcount * 2 + maxcount / 4 + 20] = {0};
		if (value.size() == 0 || value.begin() == NULL)
		{
			sprintf(strbuf, "[%u B:null]", value.size());
		}
		else
		{
			char * p = strbuf + sprintf(strbuf, "[%u B:", value.size());
			size_t limit = value.size() < maxcount ? value.size() - 1 : maxcount - 1;
			for (size_t i = 0; i < limit; i++)
			{
				p += sprintf(p, ((i + 1) % 4 == 0) ? "%02X ":"%02X", value[i]);
			}
			sprintf(p, "%02X%s", value[limit], limit < value.size() - 1 ? "...]" : "]");
		}
		os<<strbuf;
		return os;
	}

	inline std::ostream& operator<<(std::ostream& os, const base::dictionary::value_type& value)
	{
		os<<"("<<value.first<<","<<value.second<<")";
		return os;
	}

	inline std::ostream& operator<<(std::ostream& os, const base::guid& value)
	{
		static const uint8_t digitsTable[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
		const uint8_t* data = value.begin();
		char strbuf[40] = {
			digitsTable[(data[0] & 0xF0) >> 4],	digitsTable[(data[0] & 0x0F)],
			digitsTable[(data[1] & 0xF0) >> 4],	digitsTable[(data[1] & 0x0F)],
			digitsTable[(data[2] & 0xF0) >> 4],	digitsTable[(data[2] & 0x0F)],
			digitsTable[(data[3] & 0xF0) >> 4],	digitsTable[(data[3] & 0x0F)],
			'-',
			digitsTable[(data[4] & 0xF0) >> 4],	digitsTable[(data[4] & 0x0F)],
			digitsTable[(data[5] & 0xF0) >> 4],	digitsTable[(data[5] & 0x0F)],
			'-',
			digitsTable[(data[6] & 0xF0) >> 4],	digitsTable[(data[6] & 0x0F)],
			digitsTable[(data[7] & 0xF0) >> 4],	digitsTable[(data[7] & 0x0F)],
			'-',
			digitsTable[(data[8] & 0xF0) >> 4],	digitsTable[(data[8] & 0x0F)],
			digitsTable[(data[9] & 0xF0) >> 4],	digitsTable[(data[9] & 0x0F)],
			'-',
			digitsTable[(data[10]& 0xF0) >> 4],	digitsTable[(data[10]& 0x0F)],
			digitsTable[(data[11]& 0xF0) >> 4],	digitsTable[(data[11]& 0x0F)],
			digitsTable[(data[12]& 0xF0) >> 4],	digitsTable[(data[12]& 0x0F)],
			digitsTable[(data[13]& 0xF0) >> 4],	digitsTable[(data[13]& 0x0F)],
			digitsTable[(data[14]& 0xF0) >> 4],	digitsTable[(data[14]& 0x0F)],
			digitsTable[(data[15]& 0xF0) >> 4],	digitsTable[(data[15]& 0x0F)],
			'\0'
		};
		os<<strbuf;
		return os;
	}
}

#endif

